Resize
将输入图像张量按指定插值方法缩放到目标尺寸。输入/输出均为 NHWC 格式:
[batch, height, width, channel],缩放作用于 height、width 维,batch 与 channel 保持不变。
坐标变换
对输出像素坐标 \(x_{resized}\),先映射到输入浮点坐标 \(x_{orig}\)。设输入边长为
\(L_{in}\),输出边长为 \(L_{out}\),缩放比 \(s = L_{out} / L_{in}\),
则三种 coordinate_transform_mode_ 为:
高度方向同理。
插值方法
NEAREST(最邻近)
将 \(x_{orig}\)、\(y_{orig}\) 取整得到输入像素索引后直接拷贝:
ALIGN_CORNERS时用 \(\mathrm{round}\),其余模式用 \(\mathrm{floor}\)。BILINEAR(双线性,schema 中亦称 LINEAR)
对浮点坐标 \(out\) 与输入长度 \(in\):
\[\begin{split}\begin{aligned} bottom &= \max(0, \lfloor out \rfloor) \\ top &= \min(bottom + 1,\; in - 1) \\ w_{bottom} &= 1 - (out - bottom) \end{aligned}\end{split}\]先沿宽方向插值,再沿高方向插值:
\[O[h, w, c] = I[y_b, x_l, c]\, w_y\, w_x + I[y_b, x_r, c]\, w_y\, (1 - w_x) + I[y_t, x_l, c]\, (1 - w_y)\, w_x + I[y_t, x_r, c]\, (1 - w_y)\, (1 - w_x)\]CUBIC(双三次)
在每维取 4 个相邻点,权重由系数 \(a`(``cubic_coeff_`\),常用 \(-0.75\))决定:
\[\begin{split}W(a, x) = \begin{cases} ((a+2)|x| - (a+3))|x|^2 + 1, & 0 \le |x| \le 1 \\ a|x|^3 - 5a|x|^2 + 8a|x| - 4a, & 1 < |x| \le 2 \\ 0, & \text{otherwise} \end{cases}\end{split}\]先对 4 行做水平加权,再对结果做垂直加权得到输出像素。
调用前需按 method_ 完成预处理:BILINEAR 调用 PrepareResizeBilinear,
CUBIC 调用 PrepareResizeBicubic;NEAREST 无需预处理缓冲。
- 输入:
input - 输入数据的地址
param - 算子计算所需参数的结构体。其各成员见下述。
core_mask - 核掩码(仅共享存储版本使用)。
ResizeParameter定义:
1typedef enum ResizeMethod {
2 BILINEAR = 0, // 双线性(对应 schema LINEAR)
3 NEAREST = 1, // 最邻近
4 CUBIC = 2 // 双三次
5} ResizeMethod;
6
7typedef enum CoordinateTransformMode {
8 ASYMMETRIC = 0,
9 ALIGN_CORNERS = 1,
10 HALF_PIXEL = 2
11} CoordinateTransformMode;
12
13typedef struct ResizeParameter {
14 int* input_shape_; // 输入形状 [N,H,W,C],需 4 * sizeof(int)
15 int* output_shape_; // 输出形状 [N,H,W,C],需 4 * sizeof(int)
16 int* x_lefts_; // 水平索引数组,非单个值;见下方分配说明
17 int* x_rights_; // 水平右邻索引数组(BILINEAR)
18 int* y_tops_; // 垂直索引数组,非单个值;见下方分配说明
19 int* y_bottoms_; // 垂直下邻索引数组(BILINEAR)
20 void* x_weights_; // 水平权重数组,非单个值;见下方分配说明
21 void* y_weights_; // 垂直权重数组,非单个值;见下方分配说明
22 void* line_buffers_; // 插值中间行缓冲,非单个值;见下方分配说明
23 int method_; // ResizeMethod
24 int coordinate_transform_mode_; // CoordinateTransformMode
25 float cubic_coeff_; // 双三次系数 a,仅 CUBIC 使用
26} ResizeParameter;
缓冲分配说明:
以上 x_lefts_ ~ line_buffers_ 均为**指针,指向需调用方预分配的数组**,不是单个标量。
设输出高宽为 \(H_{out}\)、\(W_{out}\),通道为 \(C\),参与计算的核数为
\(N_{core}`(私有存储版本为 1),元素字节数为 :math:`S=\operatorname{sizeof}(T)\)。
input_shape_/output_shape_:各 4 个 int。BILINEAR
x_lefts_/x_rights_:各 \(W_{out}\) 个 int
y_tops_/y_bottoms_:各 \(H_{out}\) 个 int
x_weights_:\(W_{out}\) 个 float
y_weights_:\(H_{out}\) 个 float
line_buffers_:\(2 \times W_{out} \times C \times N_{core} \times S\) 字节(每核 2 行缓存)CUBIC
x_lefts_:\(4 \times W_{out}\) 个 int(每个输出列存 4 个邻域索引)
y_tops_:\(4 \times H_{out}\) 个 int(每个输出行存 4 个邻域索引)
x_weights_:\(4 \times W_{out}\) 个 float
y_weights_:\(4 \times H_{out}\) 个 float
line_buffers_:\(4 \times W_{out} \times C \times N_{core} \times S\) 字节(每核 4 行缓存)
x_rights_/y_bottoms_:CUBIC 不使用,可不分配NEAREST:上述预处理缓冲均可不分配。
- 输出:
output - 输出地址。
- 支持平台:
FT78NEMT7004
备注
FT78NE 支持 int8, fp32
MT7004 支持 fp16, fp32
共享存储版本:
-
void i8_resize_s(int8_t *input, int8_t *output, ResizeParameter *param, int core_mask)
-
void hp_resize_s(float16 *input, float16 *output, ResizeParameter *param, int core_mask)
-
void fp_resize_s(float *input, float *output, ResizeParameter *param, int core_mask)
C调用示例:
1// MT7004 示例(共享存储多核,DDR 地址)
2void TestResizeSMCFp32(int* input_shape, int* output_shape, int method,
3 int mode, float cubic_coeff, int core_mask) {
4 int core_id = get_core_id();
5 int core_num = GetCoreNum(core_mask);
6 int logic_core_id = GetLogicCoreId(core_mask, core_id);
7 float* input = (float*)0x88000000;
8 float* output = (float*)0x98000000;
9 ResizeParameter* param = (ResizeParameter*)0x90020000;
10 if (logic_core_id == 0) {
11 param->coordinate_transform_mode_ = mode;
12 param->method_ = method;
13 param->cubic_coeff_ = cubic_coeff;
14 param->input_shape_ = (int*)0x90030000;
15 memcpy(param->input_shape_, input_shape, sizeof(int) * 4);
16 param->output_shape_ = (int*)0x90040000;
17 memcpy(param->output_shape_, output_shape, sizeof(int) * 4);
18 param->line_buffers_ = (void*)0x91000000;
19 param->x_lefts_ = (int*)0x93000000;
20 param->x_rights_ = (int*)0x93100000;
21 param->y_bottoms_ = (int*)0x93200000;
22 param->y_tops_ = (int*)0x93300000;
23 param->x_weights_ = (void*)0x93400000;
24 param->y_weights_ = (void*)0x93500000;
25 if (method == BILINEAR) {
26 PrepareResizeBilinear(param);
27 } else if (method == CUBIC) {
28 PrepareResizeBicubic(param, cubic_coeff);
29 }
30 }
31 sys_bar(0, core_num);
32 fp_resize_s(input, output, param, core_mask);
33}
34
35void main() {
36 int input_shape[4] = {1, 8, 8, 4};
37 int output_shape[4] = {1, 16, 16, 4};
38 int method = BILINEAR;
39 int mode = ALIGN_CORNERS;
40 float cubic_coeff = -0.75f;
41 int core_mask = 0b1111;
42 TestResizeSMCFp32(input_shape, output_shape, method, mode, cubic_coeff, core_mask);
43}
私有存储版本:
-
void i8_resize_p(int8_t *input, int8_t *output, ResizeParameter *param)
-
void hp_resize_p(float16 *input, float16 *output, ResizeParameter *param)
-
void fp_resize_p(float *input, float *output, ResizeParameter *param)
C调用示例:
1// MT7004 示例(私有存储单核,AM 地址)
2void TestResizeAMFp32(int* input_shape, int* output_shape, int method,
3 int mode, float cubic_coeff) {
4 float* input = (float*)0x10000000;
5 float* output = (float*)0x10020000;
6 ResizeParameter* param = (ResizeParameter*)0x10052000;
7 param->coordinate_transform_mode_ = mode;
8 param->method_ = method;
9 param->cubic_coeff_ = cubic_coeff;
10 param->input_shape_ = (int*)0x10053000;
11 memcpy(param->input_shape_, input_shape, sizeof(int) * 4);
12 param->output_shape_ = (int*)0x10054000;
13 memcpy(param->output_shape_, output_shape, sizeof(int) * 4);
14 param->line_buffers_ = (void*)0x10055000;
15 param->x_lefts_ = (int*)0x10059000;
16 param->x_rights_ = (int*)0x1005D000;
17 param->y_bottoms_ = (int*)0x10061000;
18 param->y_tops_ = (int*)0x10065000;
19 param->x_weights_ = (void*)0x10069000;
20 param->y_weights_ = (void*)0x1006D000;
21 if (method == BILINEAR) {
22 PrepareResizeBilinear(param);
23 } else if (method == CUBIC) {
24 PrepareResizeBicubic(param, cubic_coeff);
25 }
26 fp_resize_p(input, output, param);
27}
28
29void main() {
30 int input_shape[4] = {1, 8, 8, 4};
31 int output_shape[4] = {1, 16, 16, 4};
32 int method = BILINEAR;
33 int mode = ALIGN_CORNERS;
34 float cubic_coeff = -0.75f;
35 TestResizeAMFp32(input_shape, output_shape, method, mode, cubic_coeff);
36}